/*
 * ParseTool.cpp
 *
 *  Created on: 2012. 10. 16.
 *      Author: dalxx
 */

#include "ParseTool.h"
#include <Arduino.h>
#undef SERIAL_TRACE_ON

namespace PLCLib {
unsigned long ParseTool::time_out=100;
const char* ParseTool::WhiteSpace=" \t\r\n";
const char* ParseTool::OperationDelimiter="&|";
const char* ParseTool::EntityDelimiter=",";


int ParseTool::EatWhite(const char* expression, int start, int end) {
	int i;
	for(i=start;i<end;i++)
	{
		if(strchr(ParseTool::WhiteSpace,expression[i])==NULL)
			break;
	}
	return i;
}

int ParseTool::EatWhite(Stream* stream) {
	int i, ch=0;


#ifdef  SERIAL_TRACE_ON
		Serial.print("EatWhite available: ");	Serial.print(stream->available());

		Serial.println();
#endif


	for(i=0;ch!=-1;i++)
	{
		ch=ParseTool::TimedPeek(stream);
#ifdef  SERIAL_TRACE_ON
		Serial.print("EatWhite peek:");	Serial.print(ch);
		Serial.print(", EatWhite stream: ");	Serial.print((int)strchr(ParseTool::WhiteSpace,ch));
		Serial.println();
#endif
		if(strchr(ParseTool::WhiteSpace, ch)!=NULL)
			ParseTool::TimedRead(stream);
		else break;
	}
	return i;
}
int ParseTool::EatWhiteBack(const char* expression, int start, int end) {
	int i;
	for(i=end-1;i>=start;i--)
	{
#ifdef  SERIAL_TRACE_ON
		Serial.print("EatWhiteBack strchr: ");	Serial.print((int)strchr(ParseTool::WhiteSpace,expression[i]));
		Serial.println();
#endif
		if(strchr(ParseTool::WhiteSpace,expression[i])==NULL)
			break;
	}
	return ++i;
}
int ParseTool::FindDelimiter(const char* expression, const char* delimiter, int start,
		int end) {
	int i;
	for(i=start;i<end;i++)
	{
		if(strchr(delimiter, expression[i])!=NULL)
			break;
		else if(expression[i]=='(')
		{
			i=ParseTool::EatParenthesis(expression, i, end);
		}
	}
	return i;
}



int ParseTool::EatParenthesis(const char* expression, int start, int end) {
	int depth=1;
	int i;
	if(expression[start]!='(') return end;
	for(i=start+1;i<end||depth!=0;i++)
	{
		if(expression[i]=='(') depth++;
		else if(expression[i]==')') depth--;
	}
	return i;
}

bool ParseTool::ReadInt(int& tar, Stream* stream, char delimiter,
		char terminator) {
	tar=stream->parseInt();
	return ParseTool::FindUntil(stream, delimiter, terminator);

}

bool ParseTool::ReadFloat(float& tar, Stream* stream, char delimiter,
		char terminator) {
	tar=stream->parseFloat();
	return ParseTool::FindUntil(stream, delimiter, terminator);
}

int ParseTool::ReadString(char* tar, const int size, Stream* stream, char delimiter,
		char terminator) {

	int _size=PLCLib::ParseTool::EatWhite(stream);
#ifdef  SERIAL_TRACE_ON
		Serial.print("1string size: ");	Serial.print(_size);
		Serial.println();
#endif

	_size=stream->readBytesUntil(delimiter, tar, size);

	tar[_size]='\0';
#ifdef  SERIAL_TRACE_ON
	Serial.print("2string size: ");	Serial.print(_size);
	Serial.print(", 2string : ");	Serial.print(tar);
	Serial.println();
#endif
	_size=PLCLib::ParseTool::EatWhiteBack(tar,0, _size);
	tar[_size]='\0';
#ifdef  SERIAL_TRACE_ON
		Serial.print("3string size: ");	Serial.print(_size);
		Serial.print(", 3string : ");	Serial.print(tar);
		Serial.println();
#endif

	if(_size==0)return 0;
	return ++_size;
}

/*bool ParseTool::FindUntil(Stream* stream, const char* delimiter,
		const char* terminator) {
	int c=0, dindex=0, tindex=0;
	c=stream->read();
	while(c>-1)
	{
		if(!stream->available())
			return false;
		c=stream->read();
		if(c==delimiter[dindex])
		{
			dindex++;
			if(delimiter[dindex]=='\0') return true;
		}
		if(c==terminator[tindex])
		{
			tindex++;
			if(terminator[tindex]=='\0') return false;
		}
	}
	return false;
}*/

bool ParseTool::FindUntil(Stream* stream, char delimiter,
		char terminator) {
	int c=0;
	while(c>-1)
	{

		c=ParseTool::TimedRead(stream);
#ifdef  SERIAL_TRACE_ON
		Serial.print("FindUntil: ");	Serial.print((char)c);
		Serial.println();
#endif
		if(c==delimiter)
		{
			return true;
		}
		if(c==terminator)
		{
			return false;
		}
	}
	return false;
}

int ParseTool::TimedRead(Stream* stream) {
	int c;
	unsigned long _startMillis = millis();
	do {
	   c = stream->read();
	    if (c >= 0) return c;
	  } while(millis() - _startMillis < ParseTool::time_out);
	  return -1;     // -1 indicates timeout
}

int ParseTool::TimedPeek(Stream* stream) {
	int c;
		int _startMillis = millis();
		do {
		   c = stream->peek();
		    if (c >= 0) return c;
		  } while(millis() - _startMillis < ParseTool::time_out);
	  return -1;     // -1 indicates timeout
}

int ParseTool::Substring(char* tar, const char* src, int start, int end, int maxsize) {
	int i;
	for(i=start;i<end&& i<start+maxsize;i++)
	{
		tar[i]=src[i];
	}
	tar[i]='\0';
	return i;
}



} /* namespace PLCLib */
